#import "NetworkManager.h"

#import "GameServer.h"
#import "TCPServer.h"
#import "NetUtilities.h"
#import "Multiplayer_Internal.h"

//CLASS INTERFACES:

@interface GameServer (Internal) <GamePeerDelegate, TCPServerDelegate>
@end

//FUNCTIONS:

static void _SetApplierFunction(const void* value, void* context)
{
	GamePeer*			peer = (GamePeer*)value;
	
	[peer setDelegate:nil];
	[peer disconnect];
}

static void _SetApplierFunction2(const void* value, void* context)
{
	void**				info = (void**)context;
	
	if(![(GamePeer*)value sendData:info[0]])
	*((BOOL*)info[2]) = NO;
}

//CLASS IMPLEMENTATIONS:

@implementation GameServer

@synthesize delegate=_delegate, advertising=_advertising;

- (id) initWithPort:(UInt16)port
{	
	if((self = [super init])) {
        pendingGamePeers = [[NSMutableSet alloc] init];
        
        _server = [[TCPServer alloc] initWithPort: port];
        [_server setDelegate:self];
        [_server startUsingRunLoop:[NSRunLoop currentRunLoop]];
    }
	
	return self;
}

- (void) dealloc
{
	[self stopAdvertisingToClients];
	
    [pendingGamePeers release];
    
	[_server stop];
	[_server setDelegate:nil];
	[_server release];

	[super dealloc];
}

- (void) setDelegate:(id<GameServerDelegate>)delegate
{
	_delegate = delegate;
	SET_DELEGATE_METHOD_BIT(0, gameServerDidStartAdvertisingToClients:);
	SET_DELEGATE_METHOD_BIT(1, gameServerWillStopAdvertisingToClients:);
    SET_DELEGATE_METHOD_BIT(2, gameServer:gamePeerDidConnect:);
}

- (UInt16) port
{
	return [_server localPort];
}

- (id) _downloadPlistWithRequest:(NSURLRequest*)request
{
	NSError*					error = nil;
	NSData*						data;
	NSURLResponse*				response;
	
	data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
	if(data && [response isKindOfClass:[NSHTTPURLResponse class]] && ([(NSHTTPURLResponse*)response statusCode] == 200))
        return [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:NULL];
	else
        REPORT_ERROR(@"Failed communicating with tracker at %@:\n%@", request, error);
	
	return nil;
}

- (BOOL) startAdvertisingToClientsWithIdentifier:(NSString*)identifier
{
	NSString*					uniqueName = [NSString stringWithFormat:@"%@:%@", _GetDeviceUniqueID(), [[NetworkManager sharedManager] networkName]];

	if(_advertising || !_IsValidGameIdentifier(identifier))
        return NO;
	if(![_server enableBonjourWithDomain:nil applicationProtocol:identifier name:uniqueName])
        return NO;
    
	_advertising = YES;
	if(TEST_DELEGATE_METHOD_BIT(0))
        [_delegate gameServerDidStartAdvertisingToClients:self];
    
	return YES;
}

- (void) stopAdvertisingToClients
{
	if(_advertising) {
		if(TEST_DELEGATE_METHOD_BIT(1))
            [_delegate gameServerWillStopAdvertisingToClients:self];
		[_server disableBonjour];
        [_server stop];
		_advertising = NO;
	}
}

- (void) server:(TCPServer*)server didOpenConnection:(TCPServerConnection*)connection
{
	GamePeer*			peer;
        
	peer = [[GamePeer alloc] initWithConnection:connection];
	if(peer) {
        [pendingGamePeers addObject: peer];
        [peer setDelegate: self];
		[peer release];
	} else
		[connection invalidate];
}

- (void) server:(TCPServer*)server didCloseConnection:(TCPServerConnection*)connection
{

}


- (void)gamePeerDidFailConnecting:(GamePeer*)p
{
    [pendingGamePeers removeObject: p];
}

- (void)gamePeerDidConnect:(GamePeer*)p
{
	if(TEST_DELEGATE_METHOD_BIT(2))
        [_delegate gameServer:self gamePeerDidConnect: p];
    [pendingGamePeers removeObject: p];   
    
}

- (void)gamePeerDidDisconnect:(GamePeer*)p
{
    [pendingGamePeers removeObject: p];
    [_delegate gameServer:self gamePeerDidDisconnect: p];
}

@end
